package data

import (
	"blog/app/blogs/internal/biz"
	"blog/internal/ent"
	"blog/internal/ent/blogs"
	"blog/internal/ent/blogsgraph"
	"blog/internal/ent/userproject"
	"context"
	"github.com/google/uuid"
	"strings"
)

func (o *blogsRepo) DelGraph(ctx context.Context, query *biz.BlogGraphQuery) (err error) {
	tx, err := o.data.db.Tx(ctx)
	if err != nil {
		return err
	}
	defer func() {
		if err != nil {
			_ = tx.Rollback()
		} else {
			err = tx.Commit()
		}
	}()
	data, err := tx.BlogsGraph.Query().Where(blogsgraph.IDEQ(query.Id)).
		Where(blogsgraph.AccountIDEQ(int(query.AccountId))).First(ctx)
	if err != nil {
		return err
	}
	if data.BlogID > 0 {
		err = tx.Blogs.UpdateOneID(int(data.BlogID)).AddGraphNum(-1).Exec(ctx)
		if err != nil {
			return
		}
	}
	if data.ProjectID > 0 {
		err = tx.UserProject.UpdateOneID(int(data.ProjectID)).AddGraphNum(-1).Exec(ctx)
		if err != nil {
			return
		}
	}
	err = tx.BlogsGraph.DeleteOneID(query.Id).Where(blogsgraph.AccountIDEQ(int(query.AccountId))).Exec(ctx)
	return
}

func (o *blogsRepo) CheckGraph(ctx context.Context, query *biz.BlogGraphQuery) (*biz.BlogGraph, error) {
	data, err := o.data.db.BlogsGraph.Query().Where(blogsgraph.IDEQ(query.Id)).
		WithBlogs().WithProjects().
		First(ctx)
	if err != nil {
		return nil, err
	}
	resp := &biz.BlogGraph{
		Id:           data.ID,
		Title:        data.Title,
		Description:  data.Description,
		IsHidden:     int64(data.IsHidden),
		Content:      data.Content,
		BrowseNumber: int64(data.BrowseNumber),
		BlogId:       int64(data.BlogID),
		ProjectId:    int64(data.ProjectID),
		CreatedAt:    data.CreatedAt,
		UpdatedAt:    data.UpdatedAt,
		AccountId:    int64(data.AccountID),
	}
	if data.Edges.Blogs != nil {
		resp.BlogTitle = data.Edges.Blogs.Title
	}
	if data.Edges.Projects != nil {
		resp.ProjectTitle = data.Edges.Projects.Title
	}
	_ = o.data.db.BlogsGraph.Update().Where(blogsgraph.IDEQ(query.Id)).AddBrowseNumber(1).Exec(ctx)
	return resp, nil
}

func (o *blogsRepo) SaveGraph(ctx context.Context, graph *biz.BlogGraph) (err error) {
	tx, err := o.data.db.Tx(ctx)
	if err != nil {
		return err
	}
	defer func() {
		if err != nil {
			_ = tx.Rollback()
		} else {
			err = tx.Commit()
		}
	}()
	if graph.Id != "" {
		var old *ent.BlogsGraph
		old, err = tx.BlogsGraph.Query().Where(blogsgraph.IDEQ(graph.Id)).First(ctx)
		if err != nil {
			return err
		}
		_, err = tx.BlogsGraph.UpdateOneID(graph.Id).Where(blogsgraph.AccountIDEQ(int(graph.AccountId))).
			SetTitle(graph.Title).
			SetDescription(graph.Description).
			SetIsHidden(int8(graph.IsHidden)).
			SetContent(graph.Content).
			SetProjectID(int(graph.ProjectId)).
			SetBlogID(int(graph.BlogId)).
			Save(ctx)
		if err != nil {
			return err
		}
		if old.ProjectID != int(graph.ProjectId) {
			if old.ProjectID > 0 {
				_, err = tx.UserProject.UpdateOneID(int(old.ProjectID)).
					AddGraphNum(-1).
					Save(ctx)
				if err != nil {
					return
				}
			}
			if graph.ProjectId > 0 {
				_, err = tx.UserProject.UpdateOneID(int(graph.ProjectId)).
					AddGraphNum(1).
					Save(ctx)
				if err != nil {
					return
				}
			}
		}
		if old.BlogID != int(graph.BlogId) {
			if old.BlogID > 0 {
				_, err = tx.Blogs.UpdateOneID(int(old.BlogID)).
					AddGraphNum(-1).
					Save(ctx)
				if err != nil {
					return
				}
			}
			if graph.BlogId > 0 {
				_, err = tx.Blogs.UpdateOneID(int(graph.BlogId)).
					AddGraphNum(1).
					Save(ctx)
				if err != nil {
					return
				}
			}
		}
	} else {
		id := strings.ReplaceAll(uuid.New().String(), "-", "")
		_, err = tx.BlogsGraph.Create().SetID(id).
			SetAccountID(int(graph.AccountId)).
			SetTitle(graph.Title).
			SetDescription(graph.Description).
			SetIsHidden(int8(graph.IsHidden)).
			SetContent(graph.Content).
			SetProjectID(int(graph.ProjectId)).
			SetBlogID(int(graph.BlogId)).
			Save(ctx)
		if err != nil {
			return
		}
		if graph.ProjectId > 0 {
			_, err = tx.UserProject.UpdateOneID(int(graph.ProjectId)).
				AddGraphNum(1).
				Save(ctx)
			if err != nil {
				return
			}
		}
		if graph.BlogId > 0 {
			_, err = tx.Blogs.UpdateOneID(int(graph.BlogId)).
				AddGraphNum(1).
				Save(ctx)
			if err != nil {
				return
			}
		}
	}

	return
}

func (o *blogsRepo) BindGraph(ctx context.Context, i int64, strings []string) (err error) {
	tx, err := o.data.db.Tx(ctx)
	if err != nil {
		return err
	}
	defer func() {
		if err != nil {
			_ = tx.Rollback()
		} else {
			err = tx.Commit()
		}
	}()
	list, err := tx.BlogsGraph.Query().Where(blogsgraph.IDIn(strings...)).All(ctx)
	if err != nil {
		return
	}
	var blogIds []int
	for _, blog := range list {
		if blog.BlogID <= 0 {
			continue
		}
		blogIds = append(blogIds, blog.BlogID)
	}
	if len(blogIds) > 0 {
		err = tx.Blogs.Update().Where(blogs.IDIn(blogIds...)).AddGraphNum(-1).Exec(ctx)
		if err != nil {
			return
		}
	}
	err = tx.Blogs.Update().Where(blogs.IDEQ(int(i))).SetGraphNum(len(strings)).Exec(ctx)
	if err != nil {
		return
	}
	err = tx.BlogsGraph.Update().Where(blogsgraph.BlogIDEQ(int(i))).Where(blogsgraph.IDNotIn(strings...)).
		SetBlogID(0).Exec(ctx)
	if err != nil {
		return
	}
	if len(strings) == 0 {
		return
	}
	err = tx.BlogsGraph.Update().Where(blogsgraph.IDIn(strings...)).SetBlogID(int(i)).Exec(ctx)
	return
}

func (o *blogsRepo) ListGraph(ctx context.Context, query *biz.BlogGraphQuery) (int64, []*biz.BlogGraph, error) {
	tx := o.data.db.BlogsGraph.Query()
	if query.Title != "" {
		tx = tx.Where(blogsgraph.TitleContains(query.Title))
	}
	if query.BlogId > 0 {
		tx = tx.Where(blogsgraph.BlogIDEQ(int(query.BlogId)))
	}
	if query.ProjectId > 0 {
		tx = tx.Where(blogsgraph.ProjectIDEQ(int(query.ProjectId)))
	}
	total, err := tx.Count(ctx)
	if err != nil {
		return 0, nil, err
	}
	list, err := tx.
		WithBlogs(func(query *ent.BlogsQuery) {
			query.Select(blogs.FieldID, blogs.FieldTitle)
		}).
		WithProjects(func(query *ent.UserProjectQuery) {
			query.Select(userproject.FieldID, userproject.FieldTitle)
		}).
		Limit(int(query.GetPageSize())).
		Offset(int(query.GetOffset())).
		Order(ent.Desc(blogsgraph.FieldCreatedAt)).
		All(ctx)
	if err != nil {
		return 0, nil, err
	}
	data := make([]*biz.BlogGraph, 0, len(list))
	for _, v := range list {
		one := &biz.BlogGraph{
			Id:           v.ID,
			Title:        v.Title,
			Description:  v.Description,
			IsHidden:     int64(v.IsHidden),
			Content:      v.Content,
			BrowseNumber: int64(v.BrowseNumber),
			BlogId:       int64(v.BlogID),
			ProjectId:    int64(v.ProjectID),
			CreatedAt:    v.CreatedAt,
			UpdatedAt:    v.UpdatedAt,
			AccountId:    int64(v.AccountID),
		}
		if v.Edges.Blogs != nil {
			one.BlogTitle = v.Edges.Blogs.Title
		}
		if v.Edges.Projects != nil {
			one.ProjectTitle = v.Edges.Projects.Title
		}
		data = append(data, one)
	}
	return int64(total), data, nil
}
